#include "mainwindow.h"
#include "ui_mainwindow.h"
//初始化静态变量
qint64 MainWindow::preUpdateTempChartTime = 0;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    initTempChartView();

    // 开始自动更新温度图
    // 如果在更新温度数据处调用，则下列代码只执行一次。showTempChartView方法中的参数替换为全局变量中的对应三个值，这三个值会不断变化。
    QTimer *updateChartViewTimer;
    updateChartViewTimer = new QTimer(this);
    connect(updateChartViewTimer, &QTimer::timeout,this,[=]() {
        // 参数为模拟数据，根据实际替换成变量
        showTempChartView(80 + rand() % 10, 30 + rand() % 10, 60 + rand() % 10);
    });
    // 每隔refreshTempChartTimeGap执行一次，也就实现定时刷新图表数据
    updateChartViewTimer->start(refreshTempChartTimeGap);
}

MainWindow::~MainWindow()
{
    delete ui;
    // 析构函数中，释放指针。
    // 删除图表相关指针
    delete globalMaxTempSplineSeres;
    delete globalMinTempSplineSeres;
    delete globalAvgTempSplineSeres;
    delete dateTimeAxisX;
    delete valueAxisY;
    delete chart;
}


void MainWindow::initTempChartView()
{
    // 创建图表；
    if (chart == NULL) {
        chart = new QChart();
    }

    // 创建坐标轴；
    if (dateTimeAxisX == NULL) {
        dateTimeAxisX = new QDateTimeAxis();
    }

    if (valueAxisY == NULL) {
        valueAxisY = new QValueAxis();
    }

    valueAxisY->setRange(0, 110);
    // 设置坐标轴标题和显示格式；
    dateTimeAxisX->setTitleText("时间/hh:mm:ss");
    valueAxisY->setTitleText("温度/℃");
    dateTimeAxisX->setFormat("hh:mm:ss");
    valueAxisY->setLabelFormat("%.2f");
    //设置坐标轴的精度；分成多少份(多少个刻度)，最小间隔为Range/(TickCount - 1)
    dateTimeAxisX->setTickCount(10);
    valueAxisY->setTickCount(10);
    // 图表添加坐标轴；
    chart->addAxis(dateTimeAxisX,Qt::AlignBottom);
    chart->addAxis(valueAxisY,Qt::AlignLeft);
    // 设置图表的标题以及图例显示；
    chart->setTitle("温度变化图");
    chart->legend()->hide();

    globalMaxTempSplineSeres = new QSplineSeries;
    globalMinTempSplineSeres = new QSplineSeries;
    globalAvgTempSplineSeres = new QSplineSeries;

    //设置最大温度曲线的颜色；
    QPen globalMaxTempPen(QColor(0xFF0000));
    globalMaxTempPen.setWidth(5);
    globalMaxTempSplineSeres->setPen(globalMaxTempPen);

    // 设置最小温度曲线的颜色；
    QPen globalMinTempPen(QColor(0x0000ff));
    globalMinTempPen.setWidth(5);
    globalMinTempSplineSeres->setPen(globalMinTempPen);

    // 设置平均温度曲线的颜色；
    QPen globalAvgTempPen(QColor(0xffa500));
    globalAvgTempPen.setWidth(5);
    globalAvgTempSplineSeres->setPen(globalAvgTempPen);

    // 图表添加线；
    chart->addSeries(globalMaxTempSplineSeres);
    chart->addSeries(globalMinTempSplineSeres);
    chart->addSeries(globalAvgTempSplineSeres);
    // 将曲线和坐标轴联系起来；
    globalMaxTempSplineSeres->attachAxis(dateTimeAxisX);
    globalMaxTempSplineSeres->attachAxis(valueAxisY);
    globalMinTempSplineSeres->attachAxis(dateTimeAxisX);
    globalMinTempSplineSeres->attachAxis(valueAxisY);
    globalAvgTempSplineSeres->attachAxis(dateTimeAxisX);
    globalAvgTempSplineSeres->attachAxis(valueAxisY);
    // 将图表放置在图表视图显示出来；
    ui->chartView->setChart(chart);
}

void MainWindow::showTempChartView(float maxTemp, float minTemp, float avgTemp)
{
    if (globalMaxTempSplineSeres == NULL ||
        globalMinTempSplineSeres == NULL ||
        globalAvgTempSplineSeres == NULL) {
        return;
    }

    // 当前时间
    QDateTime currentDateTime = QDateTime::currentDateTime();
    // 设置坐标轴范围；
    // 确保点没有填满整个图表时，实现线段从左边逐渐往右边延伸的效果。放在splineseres.append()之前
    // 数据还没有填满整个图表时，范围固定。起始时间为第一次显示的时间。填满图表后，条件不会满足，不会去设置范围，由x值自动控制
    if (globalMaxTempSplineSeres->points().size() < showTempPointMaxCount) {
        // 时间刻度最大值
        QDateTime rangeMaxDateTime;
        // 是否使用第一次计算的时间为横坐标最大时间
        bool useFirstClacRangeMax = true;
        // 记录起始时间
        if (globalMaxTempSplineSeres->points().size() == 0) {
            // 实际上画的第一个点是看不到的，第一次看到的第二个点
            chartViewFirstShowTime = currentDateTime;
        } else {
            // 如果这个函数不在定时器中执行，那else中的代码很有必要
            qint64 lastPointX = currentDateTime.toMSecsSinceEpoch();
            // 微调最大横坐标刻度值。因为有种情况是这样：温度数据更新时间间隔比图表刷新更快。
            // 比如数据100毫秒更新一次，图表我想1秒钟刷新一次。此时计算的最大横坐标刻度就偏小了。
            if (chartViewFirstShowTime.addMSecs(showTempPointMaxCount
                                                * refreshTempChartTimeGap)
                    .toMSecsSinceEpoch() < lastPointX) {
                // 设置的范围最大值小于最后一个点的x坐标，则调整成最后一个点的x坐标值
                rangeMaxDateTime = QDateTime::fromMSecsSinceEpoch(lastPointX);
                useFirstClacRangeMax = false;
            }
        }
        if (useFirstClacRangeMax) {
            rangeMaxDateTime = chartViewFirstShowTime.addMSecs(showTempPointMaxCount * refreshTempChartTimeGap);
        }
        dateTimeAxisX->setRange(chartViewFirstShowTime, rangeMaxDateTime);
    }
    // 添加最新数据
    QPointF maxTempPointF;
    maxTempPointF.setX(currentDateTime.toMSecsSinceEpoch());
    maxTempPointF.setY(maxTemp);
    globalMaxTempSplineSeres->append(maxTempPointF);

    QPointF minTempPointF;
    minTempPointF.setX(currentDateTime.toMSecsSinceEpoch());
    minTempPointF.setY(minTemp);
    globalMinTempSplineSeres->append(minTempPointF);

    QPointF avgTempPointF;
    avgTempPointF.setX(currentDateTime.toMSecsSinceEpoch());
    avgTempPointF.setY(avgTemp);
    globalAvgTempSplineSeres->append(avgTempPointF);

    // 显示固定个数，刷新图表的关键代码
    if (globalMaxTempSplineSeres->points().size() > showTempPointMaxCount) {
        // 移除最前面的一个，过时的/不显示的数据，确保点序列的个数保持固定，且为了方便获取移除旧数据后的第一个值的横坐标
        globalMaxTempSplineSeres->remove(0);
        globalMinTempSplineSeres->remove(0);
        globalAvgTempSplineSeres->remove(0);

        QList<QPointF> maxTempPoints = globalMaxTempSplineSeres->points();
        //2022.11.30 增加语句 根据当前点确定横坐标范围
        dateTimeAxisX->setRange(QDateTime::fromMSecsSinceEpoch(maxTempPoints.at(0).x()), QDateTime::fromMSecsSinceEpoch(maxTempPoints.at(maxTempPoints.size() - 1).x()));
    }
}
